﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Linq;
using System.Windows;
using System.Windows.Data;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using IssueVision.Common;
using IssueVision.EntityModel;

namespace IssueVision.ViewModel
{
    [Export(ViewModelTypes.UserMaintenanceViewModel, typeof(ViewModelBase))]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class UserMaintenanceViewModel : ViewModelBase
    {
        #region "Private Data Members"
        private enum UserMaintenanceOperation
        {
            Add,
            Delete,
            Update
        }
        private IIssueVisionModel _issueVisionModel;
        private UserMaintenanceOperation _operation;
        private string _userNameToDisplay;
        #endregion "Private Data Members"

        #region "Constructor"
        [ImportingConstructor]
        public UserMaintenanceViewModel(IIssueVisionModel issueVisionModel)
        {
            _issueVisionModel = issueVisionModel;

            // set up event handling
            _issueVisionModel.GetUsersCompleted += _issueVisionModel_GetUsersCompleted;
            _issueVisionModel.SaveChangesCompleted += _issueVisionModel_SaveChangesCompleted;
            _issueVisionModel.PropertyChanged += _issueVisionModel_PropertyChanged;

            // set initial user maintenance operation
            _userNameToDisplay = string.Empty;
            _operation = UserMaintenanceOperation.Update;
            IsUpdateUser = true;
            IsAddUser = false;

            // load all users
            _issueVisionModel.GetUsersAsync();
        }
        #endregion "Constructor"

        #region "ICleanup interface implementation"
        public override void Cleanup()
        {
            if (_issueVisionModel != null)
            {
                // unregister all events
                _issueVisionModel.GetUsersCompleted -= _issueVisionModel_GetUsersCompleted;
                _issueVisionModel.SaveChangesCompleted -= _issueVisionModel_SaveChangesCompleted;
                _issueVisionModel.PropertyChanged -= _issueVisionModel_PropertyChanged;
                // set CurrentUser back to null
                CurrentUser = null;
                // set _issueVisionModel to null
                _issueVisionModel = null;
            }
            // set properties back to null
            _allUsers = null;
            // unregister any messages for this ViewModel
            base.Cleanup();
        }
        #endregion "ICleanup interface implementation"

        #region "Public Properties"

        private IEnumerable<User> _allUsers;

        public CollectionViewSource AllUsersSource { get; private set; }

        private IEnumerable<string> _userTypeEntries;

        public IEnumerable<string> UserTypeEntries
        {
            get
            {
                if (_userTypeEntries == null)
                {
                    _userTypeEntries = new[]
                    {
                        IssueVisionServiceConstant.UserTypeUser,
                        IssueVisionServiceConstant.UserTypeAdmin
                    };
                }
                return _userTypeEntries;
            }
        }

        public User CurrentUser
        {
            get
            {
                return _issueVisionModel != null ? _issueVisionModel.CurrentEditUser : null;
            }
            private set
            {
                if (_issueVisionModel != null)
                {
                    if (!ReferenceEquals(_issueVisionModel.CurrentEditUser, value))
                    {
                        // update CurrentEditUser on the model
                        _issueVisionModel.CurrentEditUser = value;
                        RaisePropertyChanged("CurrentUser");
                    }
                }
            }
        }

        private bool _isAddUser;

        public bool IsAddUser
        {
            get { return _isAddUser; }
            private set
            {
                if (value != _isAddUser)
                {
                    _isAddUser = value;
                    RaisePropertyChanged("IsAddUser");
                }
            }
        }

        private bool _isUpdateUser;

        public bool IsUpdateUser
        {
            get { return _isUpdateUser; }
            private set
            {
                if (value != _isUpdateUser)
                {
                    _isUpdateUser = value;
                    RaisePropertyChanged("IsUpdateUser");
                }
            }
        }

        #endregion "Public Properties"

        #region "Public Commands"

        private RelayCommand _addUserCommand;

        public RelayCommand AddUserCommand
        {
            get
            {
                if (_addUserCommand == null)
                {
                    _addUserCommand = new RelayCommand(
                        () => OnAddUserCommand(),
                        () => (_issueVisionModel != null) && !(_issueVisionModel.HasChanges));
                }
                return _addUserCommand;
            }
        }

        private void OnAddUserCommand()
        {
            try
            {
                if (!_issueVisionModel.IsBusy)
                {
                    // cancel any changes before adding a new user
                    if (_issueVisionModel.HasChanges)
                    {
                        _issueVisionModel.RejectChanges();
                    }

                    CurrentUser = new User
                    {
                        PasswordQuestion = "PasswordQuestion",
                        Settings = new UserSettings { UserType = "U" }
                    };

                    _operation = UserMaintenanceOperation.Add;
                    IsUpdateUser = false;
                    IsAddUser = true;
                }
            }
            catch (Exception ex)
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(ex);
            }
        }

        private RelayCommand<User> _removeUserCommand;

        public RelayCommand<User> RemoveUserCommand
        {
            get
            {
                if (_removeUserCommand == null)
                {
                    _removeUserCommand = new RelayCommand<User>(
                        g => OnRemoveUserCommand(g),
                        g => (_issueVisionModel != null) && 
                            !(_issueVisionModel.HasChanges) && (g != null));
                }
                return _removeUserCommand;
            }
        }

        private void OnRemoveUserCommand(User g)
        {
            try
            {
                if (!_issueVisionModel.IsBusy)
                {
                    // cancel any changes before deleting a user
                    if (_issueVisionModel.HasChanges)
                    {
                        _issueVisionModel.RejectChanges();
                    }

                    // ask to confirm deleting the current user
                    DialogMessage dialogMessage = new DialogMessage(
                        this,
                        CommonResources.DeleteCurrentUserMessageBoxText,
                        s =>
                        {
                            if (s == MessageBoxResult.OK)
                            {
                                // if confirmed, removing CurrentUser
                                g.MarkAsDeleted();

                                // cache the current user name as empty string
                                _userNameToDisplay = string.Empty;

                                _operation = UserMaintenanceOperation.Delete;
                                IsUpdateUser = true;
                                IsAddUser = false;

                                _issueVisionModel.SaveChangesAsync();
                            }
                        })
                    {
                        Button = MessageBoxButton.OKCancel,
                        Caption = CommonResources.ConfirmMessageBoxCaption
                    };

                    AppMessages.PleaseConfirmMessage.Send(dialogMessage);
                }
            }
            catch (Exception ex)
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(ex);
            }
        }

        private RelayCommand _submitChangeCommand;

        public RelayCommand SubmitChangeCommand
        {
            get
            {
                if (_submitChangeCommand == null)
                {
                    _submitChangeCommand = new RelayCommand(
                        () => OnSubmitChangeCommand(),
                        () => (_issueVisionModel != null) && (_issueVisionModel.HasChanges));
                }
                return _submitChangeCommand;
            }
        }

        private void OnSubmitChangeCommand()
        {
            try
            {
                if (!_issueVisionModel.IsBusy)
                {
                    if (CurrentUser != null)
                    {
                        // following settings are there to prevent validation errors
                        CurrentUser.Password = CurrentUser.NewPassword;
                        CurrentUser.PasswordAnswer = "PasswordAnswer";
                        CurrentUser.PasswordAnswerConfirmation = "PasswordAnswer";

                        if (CurrentUser.TryValidate())
                        {
                            // cache the current user name
                            _userNameToDisplay = CurrentUser.Name;

                            // change is from User Maintenance screen
                            CurrentUser.Settings.IsUserMaintenance = 1;

                            _issueVisionModel.SaveChangesAsync();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(ex);
            }
        }

        private RelayCommand _cancelChangeCommand;

        public RelayCommand CancelChangeCommand
        {
            get
            {
                if (_cancelChangeCommand == null)
                {
                    _cancelChangeCommand = new RelayCommand(
                        () => OnCancelChangeCommand(),
                        () => (_issueVisionModel != null) && (_issueVisionModel.HasChanges));
                }
                return _cancelChangeCommand;
            }
        }

        private void OnCancelChangeCommand()
        {
            try
            {
                if (!_issueVisionModel.IsBusy)
                {
                    // ask to confirm canceling the current user in edit
                    DialogMessage dialogMessage = new DialogMessage(
                        this,
                        CommonResources.CancelCurrentUserMessageBoxText,
                        s =>
                        {
                            if (s == MessageBoxResult.OK)
                            {
                                // if confirmed, cancel any change to CurrentUser
                                _issueVisionModel.RejectChanges();
                                if (_operation == UserMaintenanceOperation.Update)
                                {
                                    // if in update operation, just refresh CurrentUser
                                    RaisePropertyChanged("CurrentUser");
                                }
                                else
                                {
                                    // if in add operation, reload all users again
                                    _issueVisionModel.GetUsersAsync();
                                }
                            }
                        })
                    {
                        Button = MessageBoxButton.OKCancel,
                        Caption = CommonResources.ConfirmMessageBoxCaption
                    };

                    AppMessages.PleaseConfirmMessage.Send(dialogMessage);
                }
            }
            catch (Exception ex)
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(ex);
            }
        }

        #endregion "Public Commands"

        #region "Private Methods"

        /// <summary>
        /// Event handler for GetUsersCompleted
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _issueVisionModel_GetUsersCompleted(object sender, ResultsArgs<User> e)
        {
            if (!e.HasError)
            {
                // cancel any changes before setting AllUsersSource
                if (_issueVisionModel.HasChanges)
                {
                    _issueVisionModel.RejectChanges();
                }

                // set AllUsersSource
                _allUsers = e.Results.OrderBy(g => g.Name);

                AllUsersSource = new CollectionViewSource {Source = _allUsers};
                AllUsersSource.View.CurrentChanging += View_CurrentChanging;
                AllUsersSource.View.CurrentChanged += View_CurrentChanged;
                // notify that AllIssuesSource has changed
                RaisePropertyChanged("AllUsersSource");

                // set CurrentUser
                if (_allUsers.Count() >= 1)
                {
                    if (_allUsers.FirstOrDefault(n => n.Name == _userNameToDisplay) == null)
                    {
                        // set the first row as the current user
                        var enumerator = _allUsers.GetEnumerator();
                        enumerator.MoveNext();
                        CurrentUser = enumerator.Current;
                    }
                    else
                    {
                        CurrentUser = _allUsers.FirstOrDefault(n => n.Name == _userNameToDisplay);
                        AllUsersSource.View.MoveCurrentTo(CurrentUser);
                    }
                }

                // set operation back to update
                _operation = UserMaintenanceOperation.Update;
                IsUpdateUser = true;
                IsAddUser = false;
            }
            else
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(e.Error);
            }
        }

        /// <summary>
        /// Event handler for CurrentChanging
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void View_CurrentChanging(object sender, CurrentChangingEventArgs e)
        {
            MessageBoxResult theResult = MessageBoxResult.OK;

            if (_issueVisionModel.HasChanges)
            {
                // ask to confirm canceling the current user in edit
                DialogMessage dialogMessage = new DialogMessage(
                    this,
                    CommonResources.CancelCurrentUserMessageBoxText,
                    s => theResult = s)
                {
                    Button = MessageBoxButton.OKCancel,
                    Caption = CommonResources.ConfirmMessageBoxCaption
                };

                AppMessages.PleaseConfirmMessage.Send(dialogMessage);

                if (theResult == MessageBoxResult.Cancel)
                {
                    e.Cancel = true;
                }
            }
        }

        /// <summary>
        /// Event handler for CurrentChanged
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void View_CurrentChanged(object sender, EventArgs e)
        {
            // cancel any changes before editing another user
            if (_issueVisionModel.HasChanges)
            {
                _issueVisionModel.RejectChanges();
            }
            // assign the new current item to CurrentUser
            CurrentUser = (User)AllUsersSource.View.CurrentItem;
        }

        /// <summary>
        /// Event handler for SaveChangesCompleted
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _issueVisionModel_SaveChangesCompleted(object sender, ResultArgs<string> e)
        {
            if (!e.HasError)
            {
                // check whether there is any warning message returned
                if (!string.IsNullOrEmpty(e.Results))
                {
                    DialogMessage dialogMessage = new DialogMessage(
                        this,
                        e.Results,
                        null)
                    {
                        Button = MessageBoxButton.OK,
                        Caption = CommonResources.WarningMessageBoxCaption
                    };

                    AppMessages.StatusUpdateMessage.Send(dialogMessage);
                }
                else
                {
                    if (_operation == UserMaintenanceOperation.Update)
                    {
                        // user update successful
                        DialogMessage dialogMessage = new DialogMessage(
                                    this,
                                    CommonResources.UserMaintenanceUpdatedText,
                                    null)
                        {
                            Button = MessageBoxButton.OK,
                            Caption = CommonResources.UserMaintenanceUpdatedCaption
                        };

                        AppMessages.StatusUpdateMessage.Send(dialogMessage);
                    }

                    // reload the user list after add/delete/update
                    _issueVisionModel.GetUsersAsync();
                }
            }
            else
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(e.Error);
            }
        }

        /// <summary>
        /// Event handler for PropertyChanged
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _issueVisionModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName.Equals("HasChanges"))
            {
                AddUserCommand.RaiseCanExecuteChanged();
                RemoveUserCommand.RaiseCanExecuteChanged();
                SubmitChangeCommand.RaiseCanExecuteChanged();
                CancelChangeCommand.RaiseCanExecuteChanged();
            }
        }

        #endregion "Private Methods"
    }
}
